package web.java.e_transaction;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Savepoint;

import org.junit.Test;

import web.java.z_JDBCUtil.DBUtil;

public class Demo01_Transaction {
	/**
	 * transaction
	 * 事务处理
	 * */
	/**
	 * |-Connection 相关，事务方法
	 * void conn.setAutoCommit(boolean autoCommit);	
	 * 	设置事务是否自动提交，默认为true自动提交，修改为false后，即改为手动提交，开启事务。
	 * void conn.rollback();	回滚事务，一般放在catch中，当数据库操作出现异常，则回滚到事务开启的点。
	 * void conn.commit();	提交事务，将操作提交给数据库进行持久性更改。
	 * SavePoint conn.setSavePoint(); 设置回滚点，返回一个SavePoint回滚点对象
	 * void conn.rollback(SavePoint point);	回滚事务，回滚到前面设置的回滚点。
	 * */
	//全局变量
	private Connection conn;
	private PreparedStatement pstmt;
	private ResultSet result;
	
	@Test
	public void borrow_money(){
		String from_sql="UPDATE money SET money=money-1000 WHERE NAME='cainter'";
		String to_sql="UPDATEs money SET money=money+1000 WHERE NAME='monster'";
		try{
			conn=DBUtil.connection();
			//打开事务
			/**
			 * 事务注意事项：
			 * 	mysql数据库中，只有InnoDB数据库引擎可以使用事务进行回滚。
			 * 	一般数据库默认引擎为MyISAM数据库引擎，不支持事务操作
			 * 	每张表都有相应的数据库引擎，需要进行事务操作的表首先更改其数据库引擎为InnoDB。
			 * 
			 * 另外：InnoBD支持外链和级联功能，MyISAM不支持外键。
			 * */
			conn.setAutoCommit(false);//关闭事务的自动提交，该为手动提交
			pstmt=conn.prepareStatement(from_sql);
			int result1=pstmt.executeUpdate();
			pstmt=conn.prepareStatement(to_sql);
			int result2=pstmt.executeUpdate();
			System.out.println(result1+":"+result2);
		}catch(SQLException e){
			e.printStackTrace();
			//当sql语句出现异常时，回滚事务
			System.out.println("SQL语句出错，准备回滚事务..."+e.getMessage());
			try {
				conn.rollback();
				System.out.println("事务回滚...");
			} catch (SQLException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}finally{
			try {
				conn.commit();
				System.out.println("事务提交...");
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			DBUtil.closeConn(conn, pstmt);
		}
	}
	
	@Test
	public void savePoint(){
		Connection conn=DBUtil.connection();
		Savepoint point=null;
		try{
			String sql_1="UPDATE USER SET deposit = deposit - 1000 WHERE NAME='cainter'";
			String sql_2="UPDATE USER SET deposit = deposit + 1000 WHERE NAME='洛宇'";
			String sql_3="UPDATE USER SET deposit = deposit - 1000 WHERE NAME='monster'";
			String sql_4="UPDATE USER SET deposit = deposit + 1000 WHERE NAME='洛天'";
			//切换事务到手动提交
			conn.setAutoCommit(false);
			pstmt=conn.prepareStatement(sql_1);
			pstmt.executeUpdate();
			pstmt=conn.prepareStatement(sql_2);
			pstmt.executeUpdate();
			
			//设置回滚点
			point=conn.setSavepoint();
			
			pstmt=conn.prepareStatement(sql_3);
			pstmt.executeUpdate();
			pstmt=conn.prepareStatement(sql_4);
			pstmt.executeUpdate();
			
			//当后面的修改出错，回滚到指定的回滚点
		}catch(SQLException e){
			try {
				conn.rollback(point);
			} catch (SQLException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}finally{
			try {
				conn.commit();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			DBUtil.closeConn(conn, pstmt);
		}
	}
}
